package com.huayun.plugin.service;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.huayun.plugin.common.TraceId;
import com.huayun.plugin.domain.MeasureData;
import com.huayun.plugin.domain.RequestMeasureData;
import com.huayun.plugin.domain.SeparationCode;
import lombok.RequiredArgsConstructor;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class MeasureCableService {
    private final Logger logger = LoggerFactory.getLogger(MeasureCableService.class);

    private final MongoTemplate mongoTemplate;
    private final ObjectMapper objectMapper = new ObjectMapper();


    /**
     * 根据输入数据进行逻辑处理，返回创建的Excel
     * @param requestMeasureData
     * @return File
     * @throws IOException
     */
    public File createMeasureFile(RequestMeasureData requestMeasureData) throws IOException {
//        logger.info("trace id: {} ,checkType: {}", TraceId.get(), requestMeasureData.checkType);
//        logger.info("trace id: {} ,measureType: {}", TraceId.get(),requestMeasureData.measureType);
//        logger.info("trace id: {} ,exportType: {}", TraceId.get(),requestMeasureData.exportType);
//        logger.info("trace id: {} ,minDistance: {}", TraceId.get(),requestMeasureData.minDistance);

        List<MeasureData> measureResult;
        if (requestMeasureData.checkType > 0) {
            // =1时是带隔离代码检查
            measureResult = measureDatabySeperationCode(requestMeasureData.measureData, requestMeasureData.exportType);
        } else {
            // =0时是不带隔离代码检查
            measureResult = measureDatabyMinDistance(requestMeasureData.measureData, requestMeasureData.exportType, requestMeasureData.minDistance);
        }

        File file = useTemplateCreateFile(measureResult);
        return file;
    }

    /**
     * 根据测量结果把数据写入excel文件
     * @param data
     * @return File
     * @throws IOException
     */
    private File useTemplateCreateFile(List<MeasureData> data) throws IOException {
        File dataFile = null;
        FileOutputStream outputStream = null;
        SXSSFWorkbook workbook = null;

        try {
            //创建文件夹，生成临时文件
            File directory = new File("cadtool/temp/");
            if (!directory.exists()) {
                if (!directory.mkdirs()) {
                    logger.error("文件夹创建失败: cadtool/temp");
                }
            }

            String name = ObjectId.get().toString();

            dataFile = new File("cadtool/temp/", name + ".xlsx");
            dataFile.createNewFile();
            outputStream = new FileOutputStream(dataFile);  // 生成文件输出流

            int rowAccessWindowSize = 1000;
            // 创建工作簿
            workbook = new SXSSFWorkbook(rowAccessWindowSize);

            SXSSFSheet sheet = workbook.createSheet();
            workbook.setSheetName(0, "线束距离检查");
            sheet.setColumnWidth(0, 4 * 256);
            sheet.setColumnWidth(1, 50 * 256);
            sheet.setColumnWidth(2, 50 * 256);
            sheet.setColumnWidth(3, 10 * 256);
//            sheet.setColumnWidth(4, 40 * 256);
//            sheet.setColumnWidth(5, 40 * 256);
            sheet.setColumnWidth(4, 10 * 256);


            // 创建第一行表头
            SXSSFRow headRow = sheet.createRow(0);
            CellStyle cellStyle = workbook.createCellStyle();
            cellStyle.setBorderBottom(BorderStyle.THIN);
            cellStyle.setBorderTop(BorderStyle.THIN);
            cellStyle.setBorderRight(BorderStyle.THIN);
            cellStyle.setBorderLeft(BorderStyle.THIN);

            XSSFFont font = (XSSFFont) workbook.createFont();
            font.setFontName("宋体");
            cellStyle.setFont(font);

            String no = "序号";
            setCellValue(0, headRow, "序号", cellStyle);
            setCellValue(1, headRow, "路径1", cellStyle);
            setCellValue(2, headRow, "路径2", cellStyle);
            setCellValue(3, headRow, "距离(mm)", cellStyle);
//            setCellValue(4, headRow, "点1", cellStyle);
//            setCellValue(5, headRow, "点2", cellStyle);
            setCellValue(4, headRow, "检查类型", cellStyle);

            int count = data.size();
            for (int i = 0; i < count; i++) {
                SXSSFRow row = sheet.createRow(i + 1);
                setCellValue(0, row, i + 1, cellStyle);
                setCellValue(1, row, data.get(i).startSegment, cellStyle);
                setCellValue(2, row, data.get(i).endSegment, cellStyle);
                setCellValue(3, row, data.get(i).minDistance, cellStyle);
//                setCellValue(4, row, data.get(i).pointStart, cellStyle);
//                setCellValue(5, row, data.get(i).pointEnd, cellStyle);
                setCellValue(4, row, data.get(i).measureType, cellStyle);

            }

            workbook.write(outputStream);
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            logger.warn("export excel fail");
            if (outputStream != null) {
                outputStream.close();
            }
            if (dataFile != null) {
                dataFile.delete();
                dataFile = null;
            }
        } finally {
            outputStream.close();
            if (workbook != null) {
                workbook.close();
            }
        }
        return dataFile;
    }

    /**
     * 设置单元格的数据和样式
     * @param columnIndex 列索引
     * @param row 单元格行
     * @param value 要写入单元格的数据
     * @param cellStyle 单元格样式
     */
    private void setCellValue(int columnIndex, SXSSFRow row, Object value, CellStyle cellStyle) {
        SXSSFCell cell = row.createCell(columnIndex);
        if (value instanceof String) {
            cell.setCellValue((String) value);
        }
        if (value instanceof Integer) {
            cell.setCellValue((Integer) value);
        }
        if (value instanceof Double) {
            cell.setCellValue((Double) value);
        }
        cell.setCellStyle(cellStyle);
    }


    /**
     * 带隔离代码的数据测量业务处理
     * @param data 测量数据
     * @param exportType 导出类型
     * @return List<MeasureData>
     */
    private List<MeasureData> measureDatabySeperationCode(List<MeasureData> data, int exportType) {
        List<MeasureData> result = new ArrayList<>();
        if (exportType == 0) { // 大于最小距离
            List<MeasureData> temp = getRequireMinSeparationDistance(data);
            //筛选出测量距离小于隔离要求距离的数据
            logger.info("temp" );
            logger.info(data.toString());
            result = temp.stream().filter(item -> item.minDistance <= item.requireSepDistance).collect(Collectors.toList());
        } else { // 所有测量
            return data;
        }
        return result;
    }

    /**
     * 普通的不带隔离代码的数据测量业务处理
     * @param data 测量数据
     * @param exportType 导出类型
     * @param minDistance 要求的最小距离
     * @return List<MeasureData>
     */
    private List<MeasureData> measureDatabyMinDistance(List<MeasureData> data, int exportType, double minDistance) {
        List<MeasureData> result;
        if (exportType == 0) { // 小于最小距离
            result = data.stream().filter(item -> item.minDistance < minDistance).collect(Collectors.toList());
        } else {
            return data;
        }
        return result;
    }

    /**
     * 带隔离代码的情况根据隔离代码信息获取其要求的距离值
     * @param data 测量信息
     * @return List<MeasureData>
     */
    public List<MeasureData> getRequireMinSeparationDistance(List<MeasureData> data) {
        //logger.info("trace id: {}, getRequireMinSeparationDistance,Data: {}", TraceId.get(), data.toString());
        List<MeasureData> measureResult = new ArrayList<>();
        List<SeparationCode> allResult = mongoTemplate.findAll(SeparationCode.class);
        //logger.info("trace id: {}, find all SeparationCode size: {}", TraceId.get(), allResult.size());
        try {
            //logger.debug("trace id: {}, MeasureData: {}", TraceId.get(), objectMapper.writeValueAsString(data));
            //logger.debug("trace id: {}, find all SeparationCode: {}", TraceId.get(), objectMapper.writeValueAsString(allResult));
        } catch (Exception ignored) {}
        for (int i = 0; i < data.size(); i++) {
            MeasureData temp = data.get(i);
            temp.requireSepDistance = 0;
            if (temp.startSeperationCode == null || temp.endSeperationCode == null) {
                temp.requireSepDistance = 0;
            } else if (temp.startSeperationCode.length() > 0 && temp.endSeperationCode.length() > 0) {
                String[] startArr = temp.startSeperationCode.split("_");
                String[] endArr = temp.endSeperationCode.split("_");
                if (startArr.length == 3 && endArr.length == 3) {
                    temp.requireSepDistance = this.getRequireMinDistance(allResult, temp.startSeperationCode, temp.endSeperationCode);
                }
            }
            measureResult.add(temp);
        }
        //logger.info("trace id: {}, find all measureResult size: {}", TraceId.get(), measureResult.size());
        try {
            //logger.debug("trace id: {}, measureResult: {}", TraceId.get(), objectMapper.writeValueAsString(measureResult));
        } catch (Exception ignored) {}
        return measureResult;
    }

    /**
     * 获取两段隔离代码要求的间距的较大的值
     * @param allCodes     所有数据
     * @param startSepCode 开始位置的隔离代码
     * @param endSepCode   结束位置的隔离代码
     * @return
     */
    public double getRequireMinDistance(List<SeparationCode> allCodes, String startSepCode, String endSepCode) {
        String[] startArr = startSepCode.split("_");
        String[] endArr = endSepCode.split("_");
        if (startArr.length == 3 && endArr.length == 3) {
            Optional<SeparationCode> optionalIPS = allCodes.stream().filter(
                    item -> ((item.getSep_Code1().equals(startArr[0]) && item.getSep_Code2().equals(endArr[0]))
                            || (item.getSep_Code1().equals(endArr[0]) && item.getSep_Code2().equals(startArr[0])))
            ).findFirst();
            int disIPS = optionalIPS.get().getMinDistance();

            Optional<SeparationCode> optionalRouting = allCodes.stream().filter(
                    item -> ((item.getSep_Code1().equals(startArr[1]) && item.getSep_Code2().equals(endArr[1]))
                            || (item.getSep_Code1().equals(endArr[1]) && item.getSep_Code2().equals(startArr[1])))
            ).findFirst();
            double disRouting = optionalIPS.get().getMinDistance();

            Optional<SeparationCode> optionalEMC = allCodes.stream().filter(
                    item -> ((item.getSep_Code1().equals(startArr[2]) && item.getSep_Code2().equals(endArr[2]))
                            || (item.getSep_Code1().equals(endArr[2]) && item.getSep_Code2().equals(startArr[2])))
            ).findFirst();
            double disEMC = optionalIPS.get().getMinDistance();

            double maxtempVal = disIPS > disRouting ? disIPS : disRouting;
            double maxDis = maxtempVal > disEMC ? maxtempVal : disEMC;

            return maxDis;
        }
        return 0;
    }
}

